<?php
namespace Illuminate\Auth;

use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Str;
use Illuminate\Contracts\Support\Arrayable;

class DatabaseUserProvider implements UserProvider {
    protected $conn; // \Illuminate\Database\ConnectionInterface
    protected $hasher; // \Illuminate\Contracts\Hashing\Hasher
    protected $table; // 表名

    public function __construct(ConnectionInterface $conn, HasherContract $hasher, $table) {
        $this->conn = $conn;
        $this->table = $table;
        $this->hasher = $hasher;
    }

    public function retrieveById($identifier) {
        $user = $this->conn->table($this->table)->find($identifier);

        return $this->getGenericUser($user);
    }
    public function retrieveByToken($identifier, $token) {
        $user = $this->getGenericUser(
            $this->conn->table($this->table)->find($identifier)
        );

        return $user && $user->getRememberToken() && hash_equals($user->getRememberToken(), $token)
            ? $user : null;
    }
    public function retrieveByCredentials(array $credentials) {
        if ( empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials)) ) return;

        $query = $this->conn->table($this->table);

        foreach ( $credentials as $key => $value ) {
            if ( Str::contains($key, 'password') ) continue;

            if ( is_array($value) || $value instanceof Arrayable ) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        $user = $query->first();

        return $this->getGenericUser($user);
    }

    public function updateRememberToken(UserContract $user, $token) {
        $this->conn->table($this->table)
            ->where($user->getAuthIdentifierName(), $user->getAuthIdentifier())
            ->update([$user->getRememberTokenName() => $token]);
    }
    public function validateCredentials(UserContract $user, array $credentials) {
        return $this->hasher->check($credentials['password'], $user->getAuthPassword());
    }

    protected function getGenericUser($user) { // \Illuminate\Auth\GenericUser
        if ( ! is_null($user) ) return new GenericUser((array) $user);
    }
}
